package Datenbank;

import java.sql.*;
import java.util.Vector;
import Applikationslogik.*;

/**
 * Bildet Objekte des Typs Person auf der relationalen Datenbank ab.
 * Die Klasse beinhaltet Methoden und Objekte zum Anlegen, Ändern, Löschen und Suchen.
 *
 * @author Daniel Mossiossian & René van Straaten
 */
public class PersonMapper {

    private static PersonMapper personMapper = null;

    /**
     * Stellt sicher, dass nur eine Istanz von PersonMapper erzeugt wird.
     *
     * @return personMapper das personMapper- Objekt
     */
    public static PersonMapper PersonMapper() {
        if (personMapper == null) {
            personMapper = new PersonMapper();
        }
        return personMapper;
    }

    /**
    * Fügt ein neues Person- Objekt in die Datenbank ein.
    * Dabei wird auch überprüft, was die bisher höhste person_id (der Primärschlüssel) ist.
    *
    * @param pe das das zu speichernde Person- Objekt
    * @return pe das bereits übergebene Objekt, jedoch mit ggf. korrigierter person_id vom Typ Person
    */
    public Person insert(Person pe) {
        Connection con = DBConnection.connection();

        try {
            Statement stmt = con.createStatement();
             //Hier wird überprüft welche person_id bisher die höhste ist.
            ResultSet rs = stmt.executeQuery(
                    "SELECT MAX(person_id) AS maxid " +
                    "FROM Person");
            if (rs.next()) {
                try {
                    // Hier wird die bisher höhste vorhandene person_id um 1 erhöht.

                    pe.set_person_id(rs.getInt("maxid") + 1);

                    stmt = con.createStatement();

                    //Die tatsächliche Einfügeoperation mit den übergebenden Attributen.
                    stmt.executeUpdate("INSERT INTO Person (person_id, raum, nachname, vorname, telefon, ist_admin, email) VALUES (" +
                            pe.get_person_id() + "," +
                            pe.get_raum() + ",'" +
                            pe.get_nachname()+ "','" +
                            pe.get_vorname()+ "'," +
                            pe.get_telefon()+ "," +
                            pe.get_ist_admin()+ ",'" +
                            pe.get_email() + "')");

                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        } catch (SQLException e2) {
            e2.printStackTrace();
        }
        // Rückgabe des angelegten Objekts pe von Typ Person

        return pe;
    }

    /**
     * Aktualisiert das übergebene Person- Objekt in der Datenbank.
     *
     * @param pe das zu aktualisierende Person- Objekt
     * @return pe das als Parameter übergebene Objekt des Typs Person
     */
    public Person update(Person pe) {
        // Stellt durch Aufruf der connection() Methode der DBConnection-Klasse, die Verbindung zur Datenbank her.
        Connection con = DBConnection.connection();

        try {
            // Leeres SQL-Statement stmt wird angelegt.
            Statement stmt = con.createStatement();

            //Statement wird ausgefüllt und als Query an die DB geschickt.
            stmt.executeUpdate("UPDATE Person " +
                    "SET person_id=" + pe.get_person_id() + "," +
                    "raum=" + pe.get_raum() + ", " +
                    "nachname='" + pe.get_nachname() + "', " +
                    "vorname='" + pe.get_vorname() + "', " +
                    "telefon=" + pe.get_telefon() + ", " +
                    "ist_admin=" + pe.get_ist_admin() + ", " +
                    "email='" + pe.get_email() + "' " +
                    "WHERE person_id=" + pe.get_person_id());

        } catch (SQLException e2) {
            e2.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
        // Das als Parameter übergebende Objekt des Typs Person wird zurückgegeben
        return pe;
    }

    /**
     * Löscht alle Daten eines Person- Objekts aus der Datenbank.
     *
     * @param pe das zu löschende Objekt
     */
    public void delete(Person pe) {
        Connection con = DBConnection.connection();

        try {
            // Leeres SQL-Statement stmt wird angelegt.
            Statement stmt = con.createStatement();

            // Werden alle Einträge in der Person Tabelle gelöscht
            stmt.executeUpdate("DELETE FROM Person " +
                    "WHERE person_id=" + pe.get_person_id());

            // Werden alle Einträge in der Teilnahme Tabelle gelöscht
            stmt.executeUpdate("DELETE FROM Berechtigung " +
                    "WHERE person_id=" + pe.get_person_id());

        } catch (SQLException e2) {
            e2.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Findet alle Personen.
     *
     * @return result Vektor mit Personen-Objekten, d.h. allen in der Datenbank angelegte Personen, zurückgegeben.
     * Bei evtl. Exceptions wird ein partiell gefüllter oder ggf.
     * auch leerer Vektor vom Typ Person zurückgeliefert.
     */
    public Vector findall_person() {
        Connection con = DBConnection.connection();
        Vector result = new Vector();

        try {
            Statement stmt = con.createStatement();


            ResultSet rs = stmt.executeQuery(

                    "SELECT * " +
                    "FROM Person " +
                    "ORDER BY person_id");

            // Für jeden Eintrag im Suchergebnis wird nun ein Person- Objekt pe erstellt.
            while (rs.next()) {
                try {
                    PersonImpl pe = new PersonImpl();
                    pe.set_person_id(rs.getInt("person_id"));
                    pe.set_raum(rs.getInt("raum"));
                    pe.set_nachname(rs.getString("nachname"));
                    pe.set_vorname(rs.getString("vorname"));
                    pe.set_telefon(rs.getInt("telefon"));
                    pe.set_ist_admin(rs.getBoolean("ist_admin"));
                    pe.set_email(rs.getString("email"));
                    result.addElement(pe);
                    // Wenn kein Titel vorhanden ist bleibt der String Titel des Vectors leer
                } catch (Exception e) {
                    e.printStackTrace();
                    //Bei einer evtl. Exception wird die while-Schleife abgebrochen.
                    break;
                }

            }
        } catch (SQLException e2) {
            e2.printStackTrace();
        }
        // Ergebnisvektor vom Typ Person wird zurückgeben.
        return result;

    }

    /**
     * Findet alle Personen außer der eingeloggten Person.
     *
     * @param person_id die ID der eingeloggten Person vom Typ int
     * @return result Ergebnisvektor vom Typ Person
     */
    public Vector findall_person_ohne_uebergebene_person(int person_id) {
        Connection con = DBConnection.connection();
        Vector result = new Vector();

        try {
            Statement stmt = con.createStatement();
            ResultSet rs = stmt.executeQuery(

                    "SELECT * " +
                    "FROM Person " +
                    "WHERE person_id !=" + person_id +
                    " ORDER BY person_id");

            // Für jeden Eintrag im Suchergebnis wird nun ein Person- Objekt pe erstellt.
            while (rs.next()) {
                try {
                    PersonImpl pe = new PersonImpl();
                    pe.set_person_id(rs.getInt("person_id"));
                    pe.set_raum(rs.getInt("raum"));
                    pe.set_nachname(rs.getString("nachname"));
                    pe.set_vorname(rs.getString("vorname"));
                    pe.set_telefon(rs.getInt("telefon"));
                    pe.set_ist_admin(rs.getBoolean("ist_admin"));
                    pe.set_email(rs.getString("email"));
                    result.addElement(pe);
                } catch (Exception e) {
                    e.printStackTrace();
                    //Bei einer evtl. Exception wird die while-Schleife abgebrochen.
                    break;
                }

            }
        } catch (SQLException e2) {
            e2.printStackTrace();
        }
        // Ergebnisvektor vom Typ Person wird zurückgeben.
        return result;
    }

    /**
     * Sucht die Datenbank nach einer Person mit der eingegebenen ID.
     *
     * @param id das Primärschlüsselattribut Person in der Datenbank
     */
    public Person findbyid(int id) {
        Connection con = DBConnection.connection();

        try {
            Statement stmt = con.createStatement();

            ResultSet rs = stmt.executeQuery(
                    "SELECT * FROM Person " +
                    "WHERE person_id =" + id);

            /*
             * Da es sich bei id um einen Primärschlüssel handelt, kann max. nur ein Tupel zurückgegeben werden.
             * Es wird geprüft, ob ein Ergebnis vorliegt. Wenn ja werden die Attribute person_id, raum,
             * nachname, vorname, telefon, ist_admin und email ausgelesen und als Typ Person zurückgegeben.
             */
            if (rs.next()) {
                try {

                    PersonImpl pe = new PersonImpl();
                    pe.set_person_id(rs.getInt("person_id"));
                    pe.set_raum(rs.getInt("raum"));
                    pe.set_nachname(rs.getString("nachname"));
                    pe.set_vorname(rs.getString("vorname"));
                    pe.set_telefon(rs.getInt("telefon"));
                    pe.set_ist_admin(rs.getBoolean("ist_admin"));
                    pe.set_email(rs.getString("email"));

                    return pe;

                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            }
        } catch (SQLException e2) {
            e2.printStackTrace();
            return null;
        }
        return null;
    }
}

